/**
 * 
 */
package remato.client.view.util;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.eclipse.core.runtime.IStatus;

import remato.client.controller.Assert;
import remato.client.controller.ModelStatus;
import remato.client.controller.exceptions.RematoClientException;


/**
 * @author petterei
 *
 * @version $Id: ReflectionHelper.java,v 1.2 2006-01-31 22:40:30 petterei Exp $
 */

public class ReflectionHelper {

	@SuppressWarnings("unchecked")
	public static <T> T invoke(String debugMessage, Object target, Method method, Object... args) {
		Assert.notNull(target, "The target instance of the invokation can not be null");
		Assert.notNull(method, "The method to be invoked can not be null.");
		T result = null;
		Throwable t = null;
		try {
			result = (T)method.invoke(target, args);
		} catch (InvocationTargetException e) {
			t = e.getTargetException();
			if (t instanceof RuntimeException) {
				throw (RuntimeException)t;
			}
		} catch (RuntimeException e) {
			throw e;
		} catch (Throwable e) {
			t = e;
		}
		if (null != t) {
			String message = " Could not invoke method " 
				+ method.getName() + " on type " 
				+ target.getClass().getSimpleName() + ", # parameters: " ;
			if (null != args) {
				message += args.length;
			} else {
				message += "'null'";
			}
			throw new RematoClientException(new ModelStatus(IStatus.ERROR,debugMessage + message, t));
		}
		return result;
	}

	public static Method retrieveMethod(String debugMessage, Class targetClass, String methodName, Class... parameterTypes) {
		Method method = null;
		try {
			method = targetClass.getMethod(methodName, parameterTypes);
		} catch (Exception e) {
			String message = " Could not retrive method: " + methodName;
			if (0 < parameterTypes.length) {
				message += " with parameter "+parameterTypes[0].getSimpleName();
			} else {
				message += " with no parameter";
			}
			message += " for core method-name: "+ methodName +", type " + targetClass.getSimpleName() ;
			throw new RematoClientException(new ModelStatus(IStatus.ERROR,debugMessage + message, e));
		}
		return method;
	}

	public static <T> T invoke(String debugMessage, Object target, String methodName, Object... args) {
		Class[] parameterTypes = new Class[args.length];
		for (int i = args.length; i-- > 0;) {
			parameterTypes[i] = args.getClass();
		}
		Method method = retrieveMethod(debugMessage, target.getClass(), methodName, parameterTypes);
		return ReflectionHelper.<T>invoke(debugMessage, target, method, args); // why is ReflectionHelper.<T> necessary here? jdt does not complaint
	} 

	
	@SuppressWarnings("unchecked")
	public static <T> Class<T> toClass(String debugMessage, String className) {
		Class<T> clazz = null;
		try {
			clazz = (Class<T>)Class.forName(className);
		} catch (ClassNotFoundException e) {
			throw new RematoClientException(new ModelStatus(IStatus.ERROR,debugMessage, e));
		}
		return clazz;
	}
	
}
